package ishaportalunittests.apis.content;

import static org.junit.Assert.assertTrue;
import gwtappcontainer.server.apis.admin.AdminAPI;
import gwtappcontainer.server.apis.admin.Roles;
import gwtappcontainer.server.apis.content.ContentAPI;
import gwtappcontainer.shared.apis.APIResponse;
import gwtappcontainer.shared.apis.APIResponse.Status;
import gwtappcontainer.shared.apis.admin.UserProp;
import gwtappcontainer.shared.apis.content.ContentProp;
import ishaportalunittests.helpers.APITestHelper;
import ishaportalunittests.helpers.Util;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserServiceFactory;


public class ContentAPITest {
	private final APITestHelper helper = new APITestHelper();
	
	@Before
	public void setUp() {
		helper.setUp();
	}
	
	@After 
	public void tearDown() {
		helper.tearDown();
	}
	
	@Test
	public void developerCanAddNewTag() {
		helper.loginAsDeveloper();
		
		ContentAPI api = new ContentAPI();
		String tag = "tag_" + UUID.randomUUID();
		
		User user = UserServiceFactory.getUserService().getCurrentUser();
		APIResponse resp = api.addNewTag(tag, user);
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		resp = api.getAllTags();
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		@SuppressWarnings("unchecked")
		List<String> tags = (List<String>) resp.object;
		assertTrue(tags.contains(tag.toUpperCase()));				
	}
	
	@Test
	public void portalAdminCanAssignUserAsContentAdmin() {
								
		String email = "test@example.com";
		addNewUser(email);		
		
		//first create the tag
		String tag = "tag_" + UUID.randomUUID();
		addNewTag(tag);
			
		//assign this tag to user
		helper.loginAsPortalAdmin();
		User user = UserServiceFactory.getUserService().getCurrentUser();
		ContentAPI contentApi = new ContentAPI();
		APIResponse resp = contentApi.assignUserAsContentAdmin(email, 
				tag, user);
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		//check if role exists
		AdminAPI adminApi = new AdminAPI();
		resp = adminApi.getRolesForUser(email);
		UserProp prop = (UserProp) resp.object;
		
		String role = Roles.CONTENT_ADMIN_PREFIX + tag.toUpperCase();
		assertTrue(Util.isRolePresent(prop.roles, role));				
	}
	
	
	
	@Test
	public void developerCannotAssignUserAsContentAdmin() {
		String email = "test@example.com";
		addNewUser(email);		
		
		//first create the tag
		String tag = "tag_" + UUID.randomUUID();
		addNewTag(tag);
			
		//login as developer and assign this tag to user
		helper.loginAsDeveloper();
		User user = UserServiceFactory.getUserService().getCurrentUser();
		ContentAPI contentApi = new ContentAPI();
		APIResponse resp = contentApi.assignUserAsContentAdmin(email, 
				tag, user);
		assertTrue(resp.statusCode == Status.ERROR_INSUFFICIENT_PERMISSION);	
	}
	
	@Test
	public void canSetContentIfContentAdmin() {
		String tag = "tag_" + UUID.randomUUID();
		addNewTag(tag);
		
		String email = "test@example.com";
		addNewUser(email);
		
		ContentAPI api = new ContentAPI();
		
		APIResponse resp = api.assignUserAsContentAdmin(email, tag, 
				helper.loginAsPortalAdmin());
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		String content = "dummy content";
		User user = helper.loginAs(email);
		resp = api.setContent(content, tag, true, user);
		
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		//ensure content can be retrieved
		resp = api.getContent(tag, user);
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		ContentProp prop = (ContentProp) resp.object;
		
		assertTrue(prop.html.equals(content));
		assertTrue(prop.publish == true);
		assertTrue(prop.tag == tag);					
	}
	
	@Test
	public void canSetContentIfPortalAdmin() {
		String tag = "tag_" + UUID.randomUUID();
		addNewTag(tag);
				
		ContentAPI api = new ContentAPI();
				
		String content = "dummy content";
		User user = helper.loginAsPortalAdmin();
		APIResponse resp = api.setContent(content, tag, false, user);
		
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		//ensure content can be retrieved
		resp = api.getContent(tag, user);
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		ContentProp prop = (ContentProp) resp.object;
		
		assertTrue(prop.html.equals(content));
		assertTrue(prop.publish == false);
		assertTrue(prop.tag == tag);				
	}
	
	@Test
	public void cannotSetContentIfNotContentAdminOrPortalAdmin() {
		String tag = "tag_" + UUID.randomUUID();
		addNewTag(tag);
				
		ContentAPI api = new ContentAPI();
				
		String content = "dummy content";
		User user = helper.loginAsPortalReadOnly();
		APIResponse resp = api.setContent(content, tag, false, user);
		
		assertTrue(resp.statusCode == Status.ERROR_INSUFFICIENT_PERMISSION);
	}
	
	@Test
	public void canGetUnpublishedContentOnlyIfValidUser() {
		String tag = "tag_" + UUID.randomUUID();
		addNewTag(tag);
				
		ContentAPI api = new ContentAPI();
				
		String content = "dummy content";
		User user = helper.loginAsPortalAdmin();
		APIResponse resp = api.setContent(content, tag, false, user);
		
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		//ensure error when not logged in		
		resp = api.getContent(tag, null);
		assertTrue(resp.statusCode == Status.ERROR_LOGIN_REQUIRED);
		
		//ensure error when invalid user
		String email = "test_" + UUID.randomUUID() + "@example.com";
		resp = api.getContent(tag, helper.loginAs(email));
		assertTrue(resp.statusCode == Status.ERROR_INVALID_USER);
		
		//ensure success if valid user
		resp = api.getContent(tag, helper.loginAsPortalUser());
		assertTrue(resp.statusCode == Status.SUCCESS);		
	}
	
	@Test
	public void anyoneCanGetPublishedContent() {
		String tag = "tag_" + UUID.randomUUID();
		addNewTag(tag);
				
		ContentAPI api = new ContentAPI();
				
		String content = "dummy content";
		User user = helper.loginAsPortalAdmin();
		APIResponse resp = api.setContent(content, tag, true, user);
		
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		//ensure content can be retrieved even without login
		resp = api.getContent(tag, null);
		assertTrue(resp.statusCode == Status.SUCCESS);
		
		ContentProp prop = (ContentProp) resp.object;
		
		assertTrue(prop.html.equals(content));
		assertTrue(prop.publish == true);
		assertTrue(prop.tag == tag);	
	}
	
	@Test
	public void getContentForInvalidTagGivesResourceNotFoundError() {
		String tag = "tag_" + UUID.randomUUID();
		
		ContentAPI api = new ContentAPI();
		
		APIResponse resp = api.getContent(tag, helper.loginAsPortalAdmin());
		assertTrue(resp.statusCode == Status.ERROR_RESOURCE_DOES_NOT_EXIST);
	}
			
	@Test
	public void nonDevelopersCannotAddNewTag() {
						
		ContentAPI api = new ContentAPI();
		String tag = "tag_" + UUID.randomUUID();
		
		helper.loginAsPortalAdmin();
		User user = UserServiceFactory.getUserService().getCurrentUser();
		APIResponse resp = api.addNewTag(tag, user);
		assertTrue(resp.statusCode == Status.ERROR_INSUFFICIENT_PERMISSION);
		
		helper.loginAsPortalReadOnly();
		user = UserServiceFactory.getUserService().getCurrentUser();
		resp = api.addNewTag(tag, user);
		assertTrue(resp.statusCode == Status.ERROR_INSUFFICIENT_PERMISSION);
		
		helper.loginAsPortalUser();
		user = UserServiceFactory.getUserService().getCurrentUser();
		resp = api.addNewTag(tag, user);
		assertTrue(resp.statusCode == Status.ERROR_INSUFFICIENT_PERMISSION);							
	}
	
	@Test
	public void cannotSetContentForInvalidTag() {
		ContentAPI api = new ContentAPI();
		String tag = "tag_" + UUID.randomUUID();
		
		APIResponse resp = api.setContent("test content", tag, true, 
				helper.loginAsPortalAdmin());
		
		assertTrue(resp.statusCode == Status.ERROR_RESOURCE_DOES_NOT_EXIST);
	}
	
	@SuppressWarnings("unchecked")
	@Test 
	public void canGetAllPublishedContents() {
		ContentAPI api = new ContentAPI();
				
		APIResponse response = api.getAllValidPublishedContents(); 
		
		//return code should be success, should be a map with no members
		assertTrue(response.statusCode == Status.SUCCESS);
		
		Map<String, String> published = (Map<String, String>) response.object;
		assertTrue(published.size() == 0);
		
		//add some tags and set contents				
		api.addNewTag("TEST", helper.loginAsDeveloper());
		api.addNewTag("test2", helper.loginAsDeveloper());
		api.addNewTag("teSt3", helper.loginAsDeveloper());
		api.addNewTag("test4", helper.loginAsDeveloper());
		
		api.setContent("content for test", "test", true, helper.loginAsPortalAdmin());
		api.setContent("content for test2", "test2", false, helper.loginAsPortalAdmin());
		api.setContent("content for test3", "test3", true, helper.loginAsPortalAdmin());
		api.setContent("content for test3", "", true, 
				helper.loginAsPortalAdmin()); //invalid content
		
		response = api.getAllValidPublishedContents();
		assertTrue(response.statusCode == Status.SUCCESS);
		
		published = (Map<String, String>) response.object;
		
		assertTrue(published.size() == 2);
		assertTrue(published.get("test").equals("content for test"));
		assertTrue(published.get("test3").equals("content for test3"));
		
	}
	
	private void addNewTag(String tag) {
		
		ContentAPI contentApi = new ContentAPI();				
		contentApi.addNewTag(tag, helper.loginAsDeveloper());
	}
	
	private void addNewUser(String email) {
				
		AdminAPI adminApi = new AdminAPI();

		adminApi.addUser(email, helper.loginAsPortalAdmin());
	}

}